/*
    This file is part of QTau
    Copyright (C) 2013-2018  Tobias "Tomoko" Platen <tplaten@posteo.de>
    Copyright (C) 2013       digited       <https://github.com/digited>
    Copyright (C) 2010-2013  HAL@ShurabaP  <https://github.com/haruneko>

    QTau is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    SPDX-License-Identifier: GPL-3.0+
*/

#ifndef JACKCONNECTOR_H
#define JACKCONNECTOR_H

#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include "Utils.h"

typedef jack_default_audio_sample_t sample_t;

#define TRANSPORT_NONE 0
#define TRANSPORT_START 1
#define TRANSPORT_STOP 2
#define TRANSPORT_ZERO 3
#define TRANSPORT_STARTPOS 4

class JackAudio {
  jack_client_t* _client = nullptr;
  jack_port_t* _write_port = nullptr;
  jack_ringbuffer_t* _write_rb = nullptr;
  jack_ringbuffer_t* _control_rb = nullptr;
  jack_port_t* _midi_port = nullptr;
  jack_ringbuffer_t* _midi_rb = nullptr;
  bool _playback = false;
  jack_transport_state_t _transport_state;
  jack_transport_state_t _previous_transport_state;
  volatile int _transport_command = 0;
  int _buffer_size = 0;
  bool _use_transport = 0;
  bool _state_changed = 0;
  int _position = 0;
  int _eventfd = 0;
  float _startpos = 0;
  static int process(jack_nframes_t nframes, void* arg);
  static int sync(jack_transport_state_t state, jack_position_t* pos,
                  void* arg);

 public:
  explicit JackAudio(bool autoconnect);
  void shutdown();
  int sampleRate();
  int writeData(void* famebuf, int bytes_per_frame);
  void changeTranportState(int command) { _transport_command = command; }
  bool isRolling() { return _transport_state == JackTransportRolling; }
  void setUseTransport(bool use_transport) { _use_transport = use_transport; }
  int getBufferSize() { return _buffer_size; }
  float* allocateBuffer();
  bool stateChanged() {
    bool retval = _state_changed;
    _state_changed = false;
    return retval;
  }
  int positionChange() {
    int retval = _position;
    _position = -1;
    return retval;
  }
  jack_transport_state_t transportState() { return _transport_state; }
  int createEFD();
  int getSamplerate() { return jack_get_sample_rate(_client); }
  int readMidiData(char* buffer, int maxlength);
  void transportStartPos(float startpos) {
    _startpos = startpos;
    _transport_command = TRANSPORT_STARTPOS;
  }
};

#endif  // JACKCONNECTOR_H
